#include <linux/module.h>
#include <linux/init.h>
#include <linux/pci.h>
#include <linux/device.h>
#include <linux/cdev.h>
#include <linux/fs.h>
#include <linux/uaccess.h>
#include <linux/slab.h>
#include <linux/pci.h>

static int my_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
{
    pr_info("my_pci: Device found, pci id: %4x:%4x\n", ent->vendor, ent->device);
    pr_info("my_pci: PCI device at bus %02x, device %02x, function %02x\n",
            pdev->bus->number,
            PCI_SLOT(pdev->devfn),
            PCI_FUNC(pdev->devfn));

    int result;
    uint32_t class_rev;
    result = pci_read_config_dword(pdev, PCI_CLASS_REVISION, &class_rev);
    if (result) {
        pr_err("my_pci: Failed to read class revision\n");
        return result;
    }
    pr_info("my_pci: class: %06x, revision: %02x\n", class_rev >> 8, class_rev & 0xff);
    pr_info("my_pci: class: %08x\n", pdev->class);

    uint32_t bar;
    int flags;
    for(int i = 0; i < 6; i++) {
        result = pci_read_config_dword(pdev, PCI_BASE_ADDRESS_0 + i * 4, &bar);
        if (result) {
            pr_err("my_pci: Failed to read BAR %d\n", i);
            return result;
        }
        flags = pci_resource_flags(pdev, i);
        pr_info("my_pci: BAR %d: %0llx %s\n", i, pci_resource_start(pdev, i),
                flags & IORESOURCE_IO ? "IO" : "MEM");
    }

    result = pci_enable_device(pdev);
    if (result) {
        pr_err("my_pci: Failed to enable PCI device\n");
        return result;
    }
    return 0;
}

static void my_pci_remove(struct pci_dev *pdev)
{
    pr_info("my_pci: Device removed\n");
    pci_disable_device(pdev);
}

static const struct pci_device_id my_pci_ids[] = {
    { PCI_DEVICE(0x8086, 0x100e) }, // Example: Intel 82540EM Gigabit Ethernet Controller
    { 0, }
};

static struct pci_driver my_pci_driver = {
    .name = "my_e1000",
    .id_table = my_pci_ids,
    .probe = my_pci_probe,
    .remove = my_pci_remove,
};

module_pci_driver(my_pci_driver);

MODULE_LICENSE("GPL");